package jsong

import (
	"bytes"
	"errors"
	"fmt"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/jsons"
	"github.com/golang/protobuf/protoc-gen-go/generator"
	"reflect"
)

// json生成struct
type StructGenerator struct {
	Json    string
	Structs []*StructInfo
}

type StructInfo struct {
	Name   string
	Fields []*FieldInfo
}

func (i *StructInfo) ToStructString() string {
	buffer := bytes.Buffer{}
	buffer.WriteString(fmt.Sprintf("type %s struct { \n", i.Name))
	for _, field := range i.Fields {
		buffer.WriteString(field.ToStructString())
	}

	buffer.WriteString("}")
	return buffer.String()
}

type FieldInfo struct {
	Name string
	Type string
	Tag  string
}

func (i *FieldInfo) ToStructString() string {
	return fmt.Sprintf("\t%s %s `%s` \n", i.Name, i.Type, i.Tag)
}

// 新建struct生成器
func NewStructGenerator(Json string) *StructGenerator {
	return &StructGenerator{Json: Json, Structs: []*StructInfo{}}
}

func (g *StructGenerator) PrintStruct() error {
	topStruct := &StructInfo{
		Name:   "GenR",
		Fields: []*FieldInfo{},
	}
	g.Structs = append(g.Structs, topStruct)
	m := make(map[string]interface{}, 0)
	err := jsons.Unmarshal([]byte(g.Json), &m)
	if err != nil {
		return err
	}
	g.genStruct(m, topStruct)

	for _, info := range g.Structs {
		fmt.Println(info.ToStructString())
	}

	return nil

}

func (g *StructGenerator) genStruct(m map[string]interface{}, structInfo *StructInfo) {
	for k, v := range m {

		g.genField(k, v, structInfo)
	}
}

func (g *StructGenerator) genField(k string, v interface{}, structInfo *StructInfo) {
	switch nv := v.(type) {
	case string:

		structInfo.Fields = append(structInfo.Fields, &FieldInfo{
			Name: generator.CamelCase(k),
			Type: "string",
			Tag:  fmt.Sprintf("json:\"%s\"", k),
		})

	case float64:
		structInfo.Fields = append(structInfo.Fields, &FieldInfo{
			Name: generator.CamelCase(k),
			Type: "float64",
			Tag:  fmt.Sprintf("json:\"%s\"", k),
		})

	case map[string]interface{}:
		newStruct := &StructInfo{
			Name:   generator.CamelCase(k),
			Fields: []*FieldInfo{},
		}
		g.Structs = append(g.Structs, newStruct)
		structInfo.Fields = append(structInfo.Fields, &FieldInfo{
			Name: generator.CamelCase(k),
			Type: generator.CamelCase(k),
			Tag:  fmt.Sprintf("json:\"%s\"", k),
		})
		g.genStruct(nv, newStruct)

	case []interface{}:
		structInfo.Fields = append(structInfo.Fields, &FieldInfo{
			Name: generator.CamelCase(k),
			Type: "[]interface{}",
			Tag:  fmt.Sprintf("json:\"%s\"", k),
		})
	default:
		panic(errors.New(fmt.Sprintf("no handle for, key:%s, type: %s, value:%v \n", k, reflect.TypeOf(v).Name(), v)))
	}
}
